中间件概念

概述

在 Express.js 中,中间件是一个非常重要的概念。它允许你在请求到达最终路由处理程序之前或之后执行一些操作。中间件可以用于日志记录、身份验证、错误处理、数据处理等多种场景。理解中间件的工作原理和如何使用它们是掌握 Express.js 的关键。

什么是中间件?

中间件是一个函数,它可以访问请求对象 (req)、响应对象 (res) 以及应用程序的请求-响应周期中的下一个中间件函数 (next)。中间件函数可以执行以下任务:

  • 执行任何代码。
  • 修改请求和响应对象。
  • 结束请求-响应周期。
  • 调用堆栈中的下一个中间件。

如果当前中间件没有结束请求-响应周期,它必须调用 next() 将控制权传递给下一个中间件,否则请求将被挂起。

中间件的类型

在 Express.js 中,中间件可以分为以下几种类型:

  1. 应用级中间件:绑定到 app 对象的中间件,使用 app.use() 或 app.METHOD() 方法。
  2. 路由级中间件:绑定到 express.Router() 实例的中间件。
  3. 错误处理中间件:专门处理错误的中间件,具有四个参数 (err, req, res, next)。
  4. 内置中间件:Express.js 自带的中间件,如 express.static。
  5. 第三方中间件:由社区提供的中间件,如 body-parser。

应用级中间件

应用级中间件绑定到 app 对象,使用 app.use() 或 app.METHOD() 方法。以下是一个简单的例子:

const express = require('express');
const app = express();

// 应用级中间件
app.use((req, res, next) => {
  console.log('Time:', Date.now());
  next();
});

app.get('/', (req, res) => {
  res.send('Hello World!');
});

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

在这个例子中,app.use() 定义了一个中间件,它会在每个请求到达时记录当前时间。next() 函数将控制权传递给下一个中间件或路由处理程序。

路由级中间件

路由级中间件绑定到 express.Router() 实例。以下是一个例子:

const express = require('express');
const app = express();
const router = express.Router();

// 路由级中间件
router.use((req, res, next) => {
  console.log('Request URL:', req.originalUrl);
  next();
});

router.get('/', (req, res) => {
  res.send('Hello Router!');
});

app.use('/router', router);

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

在这个例子中,router.use() 定义了一个中间件,它会在访问 /router 路径下的任何路由时记录请求的 URL。

错误处理中间件

错误处理中间件具有四个参数 (err, req, res, next)。它用于捕获和处理应用程序中的错误。以下是一个例子:

const express = require('express');
const app = express();

app.get('/', (req, res) => {
  throw new Error('Something went wrong!');
});

// 错误处理中间件
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).send('Something broke!');
});

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

在这个例子中,当访问 / 路径时,会抛出一个错误。错误处理中间件会捕获这个错误并返回一个 500 状态码的响应。

内置中间件

Express.js 提供了一些内置中间件,如 express.static,用于提供静态文件服务。以下是一个例子:

const express = require('express');
const app = express();

// 内置中间件
app.use(express.static('public'));

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

在这个例子中,express.static 中间件用于提供 public 目录下的静态文件。

第三方中间件

第三方中间件由社区提供,可以扩展 Express.js 的功能。例如,body-parser 中间件用于解析请求体。以下是一个例子:

const express = require('express');
const bodyParser = require('body-parser');
const app = express();

// 第三方中间件
app.use(bodyParser.json());

app.post('/submit', (req, res) => {
  res.json(req.body);
});

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

在这个例子中,body-parser 中间件用于解析 JSON 格式的请求体。

实践练习

练习 1:创建一个日志记录中间件

创建一个中间件,记录每个请求的 URL 和时间戳。

const express = require('express');
const app = express();

// 日志记录中间件
app.use((req, res, next) => {
  console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
  next();
});

app.get('/', (req, res) => {
  res.send('Hello World!');
});

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

练习 2:创建一个错误处理中间件

创建一个错误处理中间件,捕获并处理应用程序中的错误。

const express = require('express');
const app = express();

app.get('/', (req, res) => {
  throw new Error('Something went wrong!');
});

// 错误处理中间件
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).send('Something broke!');
});

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

练习 3:使用第三方中间件

使用 cookie-parser 中间件解析请求中的 cookie。

const express = require('express');
const cookieParser = require('cookie-parser');
const app = express();

// 使用第三方中间件
app.use(cookieParser());

app.get('/', (req, res) => {
  res.send(`Cookies: ${JSON.stringify(req.cookies)}`);
});

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

总结

中间件是 Express.js 的核心概念之一,它允许你在请求到达最终路由处理程序之前或之后执行一些操作。通过理解和掌握中间件的使用,你可以构建更加灵活和强大的 Express.js 应用程序。希望这篇教程能帮助你更好地理解中间件的概念和使用方法。